package zent

import (
	"errors"
	"io"
	"log"
	"net"
	"studygo/sp/a/zinx/ziface"
)

type Connection struct {
	//当前链接socket TCP套接字
	Conn *net.TCPConn

	ConnID uint32

	//当前链接的状态
	isClosed bool

	//handleAPI ziface.HandleFun

	//告知已停止的 channel
	ExitChan chan bool

	//当前链接处理的方法
	//Router ziface.IRouter

	//消息的管理msgID 对应的处理业务API
	MsgHandler ziface.IMsgHandle
}

func NewConnection(conn *net.TCPConn, connid uint32, handle ziface.IMsgHandle) *Connection {
	c := &Connection{
		Conn:     conn,
		ConnID:   connid,
		isClosed: false,
		//handleAPI: handleApi,
		//Router:   router,
		MsgHandler: handle,
		ExitChan:   make(chan bool, 1),
	}
	return c
}

//StartReader 链接的读业务方法
func (c *Connection) StartReader() {
	log.Println("Reader Goroutine is running……")
	defer log.Println("connID=", c.ConnID, " Reader is exit", " remote addr :", c.Conn.RemoteAddr())
	defer c.Stop()
	for {
		//读取客户端的数据到buf中 【目前最大512字节】
		/*buf := make([]byte, utils.GlocalObject.MaxPackageSize)
		_, err := c.Conn.Read(buf)
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("recv buf err:", err)
			continue
		}*/
		//调用当前链接所绑定的API
		/*if err := c.handleAPI(c.Conn, buf, cnt); err != nil {
			log.Println("ConnID ", c.ConnID, " handler err:", err)
			break
		}*/

		//创建一个拆包解包的对象
		dp := NewDataPack()

		//读取 客户端的 Msg head 二进制 8个字节
		headData := make([]byte, dp.GetHeadLen())

		if _, err := io.ReadFull(c.GetTcpConnection(), headData); err != nil {
			log.Println("read msg head error:", err)
			break
		}

		//拆包，得到msgID 和msgDataLen 放在msg消息中

		msg, err := dp.Unpack(headData)
		if err != nil {
			log.Println("unpack err:", err)
			break
		}
		//根据dataLen ，再次 读取 data 放在msg.data中

		var data []byte
		if msg.GetMsgLen() > 0 {
			data = make([]byte, msg.GetMsgLen())

			_, err := io.ReadFull(c.GetTcpConnection(), data)
			if err != nil {
				log.Println("read msg data error,", err)
				break
			}
		}
		msg.SetData(data)
		//得到当前链接数据的请求数据
		req := Request{
			conn: c,
			msg:  msg,
		}
		//执行注册的路由方法
		/*go func(request ziface.IRequest) {
			//从路由中，找到注册的conn 对应的router 调用
			c.Router.PreHandler(request)
			c.Router.Handler(request)
			c.Router.PostHandler(request)
		}(&req)*/
		go c.MsgHandler.DoMsgHandler(&req)

	}
}

func (c *Connection) Start() {
	log.Println("Conn Start()  connId=", c.ConnID)
	//启动从当前链接读取业务
	go c.StartReader()
	//TODO 从当前业务写业务

}

func (c *Connection) Stop() {
	log.Println("Conn Stop()  connId=", c.ConnID)
	if c.isClosed {
		return
	}
	c.isClosed = true
	_ = c.Conn.Close()

	//回收资源
	close(c.ExitChan)
}

func (c *Connection) GetTcpConnection() *net.TCPConn {
	return c.Conn
}

func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

func (c *Connection) SendMsg(msgID uint32, data []byte) error {

	if c.isClosed == true {
		return errors.New("Conn is closed ")
	}
	dp := NewDataPack()
	binaryMsg, err := dp.Pack(NewMessage(msgID, data))
	if err != nil {
		return errors.New("pack msg err ")
	}
	_, err = c.Conn.Write(binaryMsg)
	if err != nil {
		log.Println("write msg id ", msgID, " err")
		return errors.New("Write and send ")
	}
	return nil
}
